<!DOCTYPE html><html lang="[&quot;zh-CN&quot;,&quot;en&quot;,&quot;default&quot;]" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>基于若依框架的SpringBoot管理系统学习 | 爱吃薯片的熊猫の技术小站</title><meta name="author" content="爱吃薯片的熊猫"><meta name="copyright" content="爱吃薯片的熊猫"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="ffffff"><meta name="description" content="本文详细介绍了基于若依框架构建 SpringBoot 管理系统的学习过程，涵盖了框架的基本配置、功能实现及常见问题解决，帮助开发者快速上手和掌握若依框架。">
<meta property="og:type" content="article">
<meta property="og:title" content="基于若依框架的SpringBoot管理系统学习">
<meta property="og:url" content="https://ywj-ch.github.io/2024/10/24/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0/index.html">
<meta property="og:site_name" content="爱吃薯片的熊猫の技术小站">
<meta property="og:description" content="本文详细介绍了基于若依框架构建 SpringBoot 管理系统的学习过程，涵盖了框架的基本配置、功能实现及常见问题解决，帮助开发者快速上手和掌握若依框架。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://ywj-ch.github.io/img/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0.png">
<meta property="article:published_time" content="2024-10-24T07:03:12.000Z">
<meta property="article:modified_time" content="2025-02-02T12:21:02.099Z">
<meta property="article:author" content="爱吃薯片的熊猫">
<meta property="article:tag" content="springboot">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://ywj-ch.github.io/img/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0.png"><script type="application/ld+json">{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "基于若依框架的SpringBoot管理系统学习",
  "url": "https://ywj-ch.github.io/2024/10/24/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0/",
  "image": "https://ywj-ch.github.io/img/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0.png",
  "datePublished": "2024-10-24T07:03:12.000Z",
  "dateModified": "2025-02-02T12:21:02.099Z",
  "author": [
    {
      "@type": "Person",
      "name": "爱吃薯片的熊猫",
      "url": "https://ywj-ch.github.io/"
    }
  ]
}</script><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://ywj-ch.github.io/2024/10/24/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0/index.html"><link rel="preconnect" href="//cdnjs.cloudflare.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"><script>
    (() => {
      
    const saveToLocal = {
      set: (key, value, ttl) => {
        if (!ttl) return
        const expiry = Date.now() + ttl * 86400000
        localStorage.setItem(key, JSON.stringify({ value, expiry }))
      },
      get: key => {
        const itemStr = localStorage.getItem(key)
        if (!itemStr) return undefined
        const { value, expiry } = JSON.parse(itemStr)
        if (Date.now() > expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return value
      }
    }

    window.btf = {
      saveToLocal,
      getScript: (url, attr = {}) => new Promise((resolve, reject) => {
        const script = document.createElement('script')
        script.src = url
        script.async = true
        Object.entries(attr).forEach(([key, val]) => script.setAttribute(key, val))
        script.onload = script.onreadystatechange = () => {
          if (!script.readyState || /loaded|complete/.test(script.readyState)) resolve()
        }
        script.onerror = reject
        document.head.appendChild(script)
      }),
      getCSS: (url, id) => new Promise((resolve, reject) => {
        const link = document.createElement('link')
        link.rel = 'stylesheet'
        link.href = url
        if (id) link.id = id
        link.onload = link.onreadystatechange = () => {
          if (!link.readyState || /loaded|complete/.test(link.readyState)) resolve()
        }
        link.onerror = reject
        document.head.appendChild(link)
      }),
      addGlobalFn: (key, fn, name = false, parent = window) => {
        if (!false && key.startsWith('pjax')) return
        const globalFn = parent.globalFn || {}
        globalFn[key] = globalFn[key] || {}
        globalFn[key][name || Object.keys(globalFn[key]).length] = fn
        parent.globalFn = globalFn
      }
    }
  
      
      const activateDarkMode = () => {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      const activateLightMode = () => {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', 'ffffff')
        }
      }

      btf.activateDarkMode = activateDarkMode
      btf.activateLightMode = activateLightMode

      const theme = saveToLocal.get('theme')
    
          const hour = new Date().getHours()
          const isNight = hour <= 6 || hour >= 18
          if (theme === undefined) isNight ? activateDarkMode() : activateLightMode()
          else theme === 'light' ? activateLightMode() : activateDarkMode()
        
      
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        document.documentElement.classList.toggle('hide-aside', asideStatus === 'hide')
      }
    
      
    const detectApple = () => {
      if (/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)) {
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
  
    })()
  </script><script>const GLOBAL_CONFIG = {
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"未找到符合您查询的内容：${query}","hits_stats":"共找到 ${hits} 篇文章"}},
  translate: undefined,
  highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false,"highlightFullpage":false,"highlightMacStyle":false},
  copy: {
    success: '复制成功',
    error: '复制失败',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  dateSuffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'null',
  Snackbar: undefined,
  infinitegrid: {
    js: 'https://cdnjs.cloudflare.com/ajax/libs/egjs-infinitegrid/4.12.0/infinitegrid.min.js',
    buttonText: '加载更多'
  },
  isPhotoFigcaption: false,
  islazyloadPlugin: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: false,
  },
  autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: '基于若依框架的SpringBoot管理系统学习',
  isHighlightShrink: false,
  isToc: true,
  pageType: 'post'
}</script><link rel="stylesheet" href="/css/custom.css" media="defer" onload="this.media='all'"><span id="fps"></span><svg aria-hidden="true" style="position:absolute; overflow:hidden; width:0; height:0"><symbol id="icon-sun" viewBox="0 0 1024 1024"><path d="M960 512l-128 128v192h-192l-128 128-128-128H192v-192l-128-128 128-128V192h192l128-128 128 128h192v192z" fill="#FFD878" p-id="8420"></path><path d="M736 512a224 224 0 1 0-448 0 224 224 0 1 0 448 0z" fill="#FFE4A9" p-id="8421"></path><path d="M512 109.248L626.752 224H800v173.248L914.752 512 800 626.752V800h-173.248L512 914.752 397.248 800H224v-173.248L109.248 512 224 397.248V224h173.248L512 109.248M512 64l-128 128H192v192l-128 128 128 128v192h192l128 128 128-128h192v-192l128-128-128-128V192h-192l-128-128z" fill="#4D5152" p-id="8422"></path><path d="M512 320c105.888 0 192 86.112 192 192s-86.112 192-192 192-192-86.112-192-192 86.112-192 192-192m0-32a224 224 0 1 0 0 448 224 224 0 0 0 0-448z" fill="#4D5152" p-id="8423"></path></symbol><symbol id="icon-moon" viewBox="0 0 1024 1024"><path d="M611.370667 167.082667a445.013333 445.013333 0 0 1-38.4 161.834666 477.824 477.824 0 0 1-244.736 244.394667 445.141333 445.141333 0 0 1-161.109334 38.058667 85.077333 85.077333 0 0 0-65.066666 135.722666A462.08 462.08 0 1 0 747.093333 102.058667a85.077333 85.077333 0 0 0-135.722666 65.024z" fill="#FFB531" p-id="11345"></path><path d="M329.728 274.133333l35.157333-35.157333a21.333333 21.333333 0 1 0-30.165333-30.165333l-35.157333 35.157333-35.114667-35.157333a21.333333 21.333333 0 0 0-30.165333 30.165333l35.114666 35.157333-35.114666 35.157334a21.333333 21.333333 0 1 0 30.165333 30.165333l35.114667-35.157333 35.157333 35.157333a21.333333 21.333333 0 1 0 30.165333-30.165333z" fill="#030835" p-id="11346"></path></symbol></svg><!-- hexo injector head_end start --><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiperstyle.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/animate.min.css" media="print" onload="this.media='screen'"><!-- hexo injector head_end end --><meta name="generator" content="Hexo 7.3.0"></head><body><div id="web_bg" style="background-image: url(/img/背景图3.jpg);"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img text-center"><img src="/img/loading.gif" data-original="/img/butterfly-icon.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data text-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">6</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">9</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">3</div></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><span class="site-page group hide"><i class="fa-fw fa fa-list"></i><span> 列表</span><i class="fas fa-chevron-down"></i></span><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/picture/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/comments/"><i class="fa-fw fas fa-envelope-open"></i><span> 留言板</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url(/img/基于若依框架的SpringBoot管理系统学习.png);"><nav id="nav"><span id="blog-info"><a class="nav-site-title" href="/"><span class="site-name">爱吃薯片的熊猫の技术小站</span></a><a class="nav-page-title" href="/"><span class="site-name">基于若依框架的SpringBoot管理系统学习</span></a></span><div id="menus"><div id="search-button"><span class="site-page social-icon search"><i class="fas fa-search fa-fw"></i></span></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><span class="site-page group hide"><i class="fa-fw fa fa-list"></i><span> 列表</span><i class="fas fa-chevron-down"></i></span><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/picture/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/comments/"><i class="fa-fw fas fa-envelope-open"></i><span> 留言板</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><span class="site-page"><i class="fas fa-bars fa-fw"></i></span></div></div></nav><div id="post-info"><h1 class="post-title">基于若依框架的SpringBoot管理系统学习</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2024-10-24T07:03:12.000Z" title="发表于 2024-10-24 15:03:12">2024-10-24</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2025-02-02T12:21:02.099Z" title="更新于 2025-02-02 20:21:02">2025-02-02</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">学习笔记</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">总字数:</span><span class="word-count">7.1k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>24分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title=""><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">浏览量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="container post-content" id="article-container"><h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><blockquote>
<p>在现代企业开发中，快速搭建高效、稳定的管理系统是一个常见的需求。而若依框架作为一个基于 SpringBoot 的开源管理系统框架，凭借其模块化设计、便捷的代码生成工具以及优秀的前端整合方案，成为了许多开发者的首选。对于初学者来说，若依框架不仅是学习 SpringBoot 开发的良好切入点，也是深入理解后台管理系统开发流程的最佳实践平台。</p>
<p>本文将结合学习若依框架的实际过程，从框架搭建到核心功能实现，对其中的重要知识点和开发技巧进行深入解析，帮助读者快速上手并掌握若依框架的使用技巧，同时为开发自己的管理系统打下坚实的基础。</p>
</blockquote>
<h4 id="一、什么是若依？"><a href="#一、什么是若依？" class="headerlink" title="一、什么是若依？"></a>一、什么是若依？</h4><h5 id="1-概述"><a href="#1-概述" class="headerlink" title="1.概述"></a>1.概述</h5><blockquote>
<p>若依框架（RuoYi）是一个基于 SpringBoot 和 Vue 的快速开发平台，常用于构建后台管理系统。它采用前后端分离的架构，前端使用 Vue.js，后端使用 SpringBoot，数据库则支持多种类型（如 MySQL、MariaDB 等）。框架集成了一些主流的开源组件，如 MyBatis、Redis、Druid、Swagger 等，使得开发人员能够快速搭建和扩展项目功能。</p>
</blockquote>
<blockquote>
<p>gitee 地址：</p>
<p>后端 <a target="_blank" rel="noopener" href="https://gitee.com/y_project/RuoYi">https://gitee.com/y_project&#x2F;RuoYi</a></p>
<p>前端 <a target="_blank" rel="noopener" href="https://gitee.com/y_project/RuoYi-Vue">https://gitee.com/y_project&#x2F;RuoYi-Vue</a></p>
</blockquote>
<blockquote>
<p>技术版本：</p>
<ul>
<li>JDK &gt;&#x3D; 1.8</li>
<li>MySQL &gt;&#x3D; 5.7</li>
<li>Maven &gt;&#x3D; 3.0</li>
<li>Node &gt;&#x3D; 12</li>
<li>Redis &gt;&#x3D; 3</li>
</ul>
</blockquote>
<h5 id="2-若依框架的特点"><a href="#2-若依框架的特点" class="headerlink" title="2.若依框架的特点"></a>2.若依框架的特点</h5><blockquote>
<ul>
<li>模块化设计：内置了用户管理、角色权限、菜单管理、操作日志、定时任务等常见的管理系统功能模块，可以快速搭建企业级应用。</li>
<li>前后端分离：前端与后端独立开发和部署，提高了开发效率和用户体验。</li>
<li>丰富的技术栈集成：集成了多种常用的技术和工具（如 MyBatis 做数据持久化，Redis 做缓存，Druid 作为数据库连接池），简化了开发过程。</li>
<li>高扩展性：代码结构清晰，支持二次开发，可以根据业务需求进行自定义扩展。</li>
</ul>
</blockquote>
<h5 id="3-若依框架的目录结构"><a href="#3-若依框架的目录结构" class="headerlink" title="3.若依框架的目录结构"></a>3.若依框架的目录结构</h5><blockquote>
<p>若依的后端项目主要分为六个模块，他们之间的依赖关系如下图所示：</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_59f382bd.png" alt="pic_59f382bd.png"></p>
<p>下面我们来分析一下每个模块的具体功能</p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_e9c40141.png" alt="pic_e9c40141.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_1c2520b9.png" alt="pic_1c2520b9.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_1e9d8b33.png" alt="pic_1e9d8b33.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_aa8ccf3b.png" alt="pic_aa8ccf3b.png"></p>
<blockquote>
<p>从上面的几张图我们可以看出若依的主要框架包括 admin、common、framework 和 system，至于 quartz 和 generator 它们并不是必须的，但是有了它们，可以大大加快我们程序的开发速度，后面我们会讲到如何使用。</p>
</blockquote>
<p>若依的配置文件主要放在-admin 包中</p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_16f83402.png" alt="pic_16f83402.png"></p>
<p>接下来是项目相关的数据库表</p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_3d67c75b.png" alt="pic_3d67c75b.png"></p>
<p>然后让我们来看看前端的项目结构</p>
<blockquote>
<p>这张图完整了列出了前端项目的框架，但是如果你像我一样重心放在后端开发，那其实只需要了解其中一部份模块的功能就行了，下面这张图列出了后端人员经常需要用到的几个模块。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_39357e97.png" alt="pic_39357e97.png"></p>
<p>下面们来分析一下若依后端的具体代码</p>
<blockquote>
<p>首先从 Controller 开始，若依框架中的 Controller 都继承了 BaseController 类，实现了基本的数据分页展示功能、用户登录相关方法、以及请求成功或者失败后的相关处理。可以说，若依的这个 BaseController 类基本上实现了业务开发所要用到的大多数常用功能。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_8f67fd18.png" alt="pic_8f67fd18.png"></p>
<blockquote>
<p>然后是我们比较关心的返回对象的封装，若依将返回对象分为了两类，一类是分页查询返回对象，另一类是增删改查返回对象。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_9d46515e.png" alt="pic_9d46515e.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_b2b81c37.png" alt="pic_b2b81c37.png"></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@PreAuthorize(&quot;@ss.hasPermi(&#x27;manage:partner:list&#x27;)&quot;)</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/list&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> TableDataInfo <span class="title function_">list</span><span class="params">(Partner partner)</span></span><br><span class="line">    &#123;</span><br><span class="line">        startPage();</span><br><span class="line">        List&lt;PartnerVo&gt; list = partnerService.selectPartnerVOList(partner);</span><br><span class="line">        <span class="keyword">return</span> getDataTable(list);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/captchaImage&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> AjaxResult <span class="title function_">getCode</span><span class="params">(HttpServletResponse response)</span> <span class="keyword">throws</span> IOException</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">AjaxResult</span> <span class="variable">ajax</span> <span class="operator">=</span> AjaxResult.success();</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">captchaEnabled</span> <span class="operator">=</span> configService.selectCaptchaEnabled();</span><br><span class="line">        ajax.put(<span class="string">&quot;captchaEnabled&quot;</span>, captchaEnabled);</span><br><span class="line">        <span class="keyword">if</span> (!captchaEnabled)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> ajax;</span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>值得一提的是@PreAuthorize 注解是 Spring Security 的一个权限认证注解，它与前端联调之后能够实现权限控制访问。</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@PreAuthorize(&quot;@ss.hasPermi(&#x27;manage:partner:edit&#x27;)&quot;)</span></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">&lt;el-button link type=<span class="string">&quot;primary&quot;</span> <span class="meta">@click</span>=<span class="string">&quot;resetPassword(scope.row)&quot;</span> v-hasPermi=<span class="string">&quot;[&#x27;manage:partner:edit&#x27;]&quot;</span>&gt;重置密码&lt;/el-button&gt;</span><br></pre></td></tr></table></figure>

<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_c06ad374.png" alt="pic_c06ad374.png"></p>
<p>前后端交互流程：</p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_e4586998.png" alt="pic_e4586998.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_471e64aa.png" alt="pic_471e64aa.png"></p>
<h4 id="二、若依框架的项目搭建"><a href="#二、若依框架的项目搭建" class="headerlink" title="二、若依框架的项目搭建"></a>二、若依框架的项目搭建</h4><h5 id="1-后端项目初始化配置"><a href="#1-后端项目初始化配置" class="headerlink" title="1.后端项目初始化配置"></a>1.后端项目初始化配置</h5><h6 id="配置数据库"><a href="#配置数据库" class="headerlink" title="配置数据库"></a>配置数据库</h6><blockquote>
<p>将后端代码克隆的本地后会有两个 sql 脚本，先创建好你的数据库然后修改数据库连接配置</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">spring:</span><br><span class="line">  datasource:</span><br><span class="line">    druid:</span><br><span class="line">      url: jdbc:mysql:<span class="comment">//localhost:3306/ruoyi?</span></span><br><span class="line">      useUnicode=<span class="literal">true</span>&amp;characterEncoding=utf8&amp;serverTimezone=UTC</span><br><span class="line">      username: your_db_username</span><br><span class="line">      password: your_db_password</span><br></pre></td></tr></table></figure>

<blockquote>
<p>ruoyi 是数据库的名字，然后执行下面的 sql 脚本就行了。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_3c915a97.png" alt="pic_3c915a97.png"></p>
<h6 id="配置-Redis-缓存"><a href="#配置-Redis-缓存" class="headerlink" title="配置 Redis 缓存"></a>配置 Redis 缓存</h6><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">spring:</span><br><span class="line">  redis:</span><br><span class="line">    host: localhost</span><br><span class="line">    port: <span class="number">6379</span></span><br><span class="line">    password: your_redis_password</span><br></pre></td></tr></table></figure>

<blockquote>
<p>注意：启动项目之前记得一定要把 Redis 打开，不然会报错。</p>
</blockquote>
<h6 id="依赖管理"><a href="#依赖管理" class="headerlink" title="依赖管理"></a>依赖管理</h6><blockquote>
<p>若依框架的依赖管理主要使用 Maven，<code>pom.xml</code>文件配置了各种依赖，包括 Spring Boot、MyBatis、Redis、Swagger 等。以下是主要依赖的说明：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.mybatis.spring.boot&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;mybatis-spring-boot-starter&lt;/artifactId&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;com.alibaba&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;druid&lt;/artifactId&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;spring-boot-starter-data-redis&lt;/artifactId&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br><span class="line">&lt;dependency&gt;</span><br><span class="line">    &lt;groupId&gt;io.springfox&lt;/groupId&gt;</span><br><span class="line">    &lt;artifactId&gt;springfox-boot-starter&lt;/artifactId&gt;</span><br><span class="line">    &lt;version&gt;<span class="number">3.0</span><span class="number">.0</span>&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure>

<h5 id="2-启动项目"><a href="#2-启动项目" class="headerlink" title="2.启动项目"></a>2.启动项目</h5><blockquote>
<p>启动后端项目：在<code>ruoyi-admin</code>目录下执行<code>RuoYiApplication</code>类中的<code>main</code>方法，启动 SpringBoot 后端服务。</p>
<p>启动前端项目：在<code>ruoyi-ui</code>目录下，执行以下命令安装依赖并启动前端服务：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">npm install</span><br><span class="line">npm run dev</span><br></pre></td></tr></table></figure>

<h5 id="3-界面展示"><a href="#3-界面展示" class="headerlink" title="3.界面展示"></a>3.界面展示</h5><blockquote>
<p>成功启动后页面会自动跳转到如下登录界面，登录密码默认是 admin123，若依的密码使用了 MD5 加密存储，所以在数据库里面是看不到的。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_44fe88e3.png" alt="pic_44fe88e3.png"></p>
<h5 id="4-功能详讲"><a href="#4-功能详讲" class="headerlink" title="4.功能详讲"></a>4.功能详讲</h5><blockquote>
<p>若依框架的菜单功能是后台管理系统的核心部分，涵盖了系统管理、监控、工具等多种模块。以下是若依系统默认的菜单结构和功能介绍：</p>
<h6 id="1-系统管理"><a href="#1-系统管理" class="headerlink" title="1. 系统管理"></a>1. 系统管理</h6><p>主要用于管理系统中的基础设置和权限控制，包括用户、角色、菜单等内容。主要功能如下：</p>
<ul>
<li>用户管理<br>管理系统中的用户信息，包括新增、编辑、删除用户，以及为用户分配角色和重置密码等操作。</li>
<li>角色管理<br>定义系统中的角色，并为角色分配菜单权限。可以设置角色的权限范围，控制其可访问的菜单项。</li>
<li>菜单管理<br>用于配置系统的菜单显示和访问权限，支持添加、编辑、删除菜单项。可以设置菜单的类型（目录、菜单、按钮）、排序、图标等信息。</li>
<li>部门管理<br>维护系统的组织架构，支持树形结构显示部门信息。可以新增、编辑、删除部门，以及查看部门成员。</li>
<li>岗位管理<br>定义系统中的岗位信息，用于关联用户岗位。可以新增、编辑、删除岗位。</li>
<li>字典管理<br>管理系统中的字典数据，如状态、性别等常用数据项。可以为每个字典项设置标签和值。</li>
<li>参数设置<br>用于管理系统中的配置参数，可以动态修改参数值而无需重启服务。</li>
<li>通知公告<br>发布和管理系统内的公告信息，支持查看公告的详细内容。</li>
</ul>
<h6 id="2-系统监控"><a href="#2-系统监控" class="headerlink" title="2. 系统监控"></a>2. 系统监控</h6><p>主要用于监控系统的运行状态、日志记录等内容，帮助运维人员管理和排查系统问题。主要功能包括：</p>
<ul>
<li>在线用户<br>显示当前在线的用户列表，可以查看用户登录信息和强制下线。</li>
<li>定时任务<br>管理系统中的定时任务（调度任务），支持任务的新增、编辑、删除，以及手动执行和暂停任务。若依默认使用 Quartz 作为定时任务调度器。</li>
<li>操作日志<br>记录用户的操作行为，如新增、编辑、删除等操作，便于审计和问题追踪。</li>
<li>登录日志<br>记录用户的登录历史，包括登录时间、IP 地址、登录状态等信息。</li>
<li>系统日志<br>显示系统的运行日志，便于运维人员查看和分析问题。</li>
</ul>
<h6 id="3-系统工具"><a href="#3-系统工具" class="headerlink" title="3. 系统工具"></a>3. 系统工具</h6><p>提供一些开发和运维相关的工具，帮助开发人员和运维人员提高工作效率。主要功能包括：</p>
<ul>
<li>代码生成<br>根据数据库表结构自动生成基础的代码模板，包括 Controller、Service、Mapper、Entity、Vue 页面等，大幅提高开发效率。支持自定义生成策略。</li>
<li>系统接口<br>提供系统 API 的在线文档，基于 Swagger 生成，支持在线测试和接口文档查看。</li>
<li>表单构建<br>可视化创建表单，支持生成 Vue 表单页面，简化前端开发工作。</li>
</ul>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_0ed0d635.png" alt="pic_0ed0d635.png"></p>
<h5 id="5-若依的代码生成器功能"><a href="#5-若依的代码生成器功能" class="headerlink" title="5.若依的代码生成器功能"></a>5.若依的代码生成器功能</h5><blockquote>
<p>这里就用到了若依的 generator 模块，若依框架的<code>generator</code>模块是一个代码生成器模块，用于自动生成基础的 CRUD 代码和页面模板。这个模块极大地提高了开发效率，尤其是在开发后台管理系统时，减少了重复性的工作。下面是对<code>generator</code>模块的详细讲解：</p>
</blockquote>
<h6 id="1-generator模块的主要功能"><a href="#1-generator模块的主要功能" class="headerlink" title="1. generator模块的主要功能"></a>1. <code>generator</code>模块的主要功能</h6><blockquote>
<ul>
<li>根据数据库表结构生成代码：可以通过解析数据库表结构自动生成对应的 Java 代码和 Vue 前端代码，包括 Controller、Service、Mapper、Entity（实体类）以及前端的页面（如列表页、表单页）。</li>
<li>支持自定义模板：可以根据需求自定义代码生成的模板，灵活控制生成代码的风格和内容。</li>
<li>可配置性强：支持根据生成选项定制生成的代码，例如是否生成分页查询、是否生成插入、删除、更新方法等。</li>
<li>大幅减少重复开发工作量：生成的代码可以作为基础模板，开发人员只需根据业务需求做个性化调整即可。</li>
</ul>
</blockquote>
<h6 id="2-generator模块的使用步骤"><a href="#2-generator模块的使用步骤" class="headerlink" title="2. generator模块的使用步骤"></a>2. <code>generator</code>模块的使用步骤</h6><blockquote>
<h6 id="2-1-进入代码生成器界面"><a href="#2-1-进入代码生成器界面" class="headerlink" title="2.1 进入代码生成器界面"></a>2.1 进入代码生成器界面</h6><ul>
<li>在后台管理系统中，点击左侧菜单的“系统工具” -&gt; “代码生成”即可进入代码生成器的管理界面。</li>
<li>该界面显示了所有从数据库中读取的表信息，包括表名、表描述、创建时间等</li>
</ul>
</blockquote>
<h6 id=""><a href="#" class="headerlink" title=""></a><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_33165d4b.png" alt="pic_33165d4b.png"></h6><blockquote>
<h6 id="2-2-配置生成参数"><a href="#2-2-配置生成参数" class="headerlink" title="2.2 配置生成参数"></a>2.2 配置生成参数</h6><p>选择需要生成代码的数据库表后，点击“生成配置”按钮进入配置页面，可以对生成的代码进行一些参数配置：</p>
<ul>
<li>生成模块名：可以指定代码所属的模块名称。</li>
<li>生成包路径：用于指定生成的 Java 代码的包路径。</li>
<li>生成模板：用于指定表的类型，分别有单表、树表和主子表。</li>
<li>上级菜单：分配到指定菜单下。</li>
</ul>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_9ae66709.png" alt="pic_9ae66709.png"></p>
<blockquote>
<h6 id="2-3-生成代码"><a href="#2-3-生成代码" class="headerlink" title="2.3 生成代码"></a>2.3 生成代码</h6><ul>
<li>配置完成后，点击“生成代码”按钮，系统会根据配置自动生成对应的 Java 代码和 Vue 前端代码。</li>
<li>生成的代码会自动打包成一个压缩文件，包含了后端和前端的代码模板，下载后可以解压并将代码复制到项目中进行个性化修改。</li>
<li>能够对生成的代码进行预览。</li>
</ul>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_8d7736e5.png" alt="pic_8d7736e5.png"></p>
<h6 id="3-生成的代码结构"><a href="#3-生成的代码结构" class="headerlink" title="3. 生成的代码结构"></a>3. 生成的代码结构</h6><blockquote>
<p>生成的代码分为后端代码和前端代码，具体结构如下：</p>
<h6 id="3-1-后端代码"><a href="#3-1-后端代码" class="headerlink" title="3.1 后端代码"></a>3.1 后端代码</h6><ul>
<li>Controller 层：负责处理 HTTP 请求，将请求分发给 Service 层，并将响应结果返回给前端。生成的 Controller 代码包含了基本的 CRUD 操作。</li>
<li>Service 层：负责业务逻辑的处理。生成的 Service 代码通常包含接口和实现类。</li>
<li>Mapper 层：MyBatis 的 Mapper 接口，用于执行数据库操作。生成的 Mapper 包含基本的增删改查方法。</li>
<li>Entity 类：表示数据库表的实体类，与表的结构对应。</li>
<li>Mapper XML：MyBatis 的 SQL 映射文件，包含了 CRUD 操作的 SQL 语句。</li>
</ul>
<h6 id="3-2-前端代码"><a href="#3-2-前端代码" class="headerlink" title="3.2 前端代码"></a>3.2 前端代码</h6><ul>
<li>列表页面（<code>xxx.vue</code>）：用于显示数据列表，支持分页、查询、增删改等操作。</li>
<li>新增&#x2F;编辑页面：用于添加和修改数据的表单界面。</li>
<li>前端接口文件（<code>api/xxx.js</code>）：定义了前端对后端的请求方法，如获取列表数据、添加、删除等操作。</li>
</ul>
</blockquote>
<h6 id="4-代码生成器的自定义"><a href="#4-代码生成器的自定义" class="headerlink" title="4. 代码生成器的自定义"></a>4. 代码生成器的自定义</h6><blockquote>
<p>若依的<code>generator</code>模块支持自定义模板和生成逻辑，满足不同项目的定制化需求：</p>
<h6 id="4-1-自定义代码生成模板"><a href="#4-1-自定义代码生成模板" class="headerlink" title="4.1 自定义代码生成模板"></a>4.1 自定义代码生成模板</h6><ul>
<li>若依的代码生成器使用 Freemarker 模板引擎，所有的生成模板都存放在<code>resources/vm</code>目录下。</li>
<li>可以根据项目的规范和需求，修改默认模板或者添加新的模板来定制生成的代码格式。</li>
</ul>
<h6 id="4-2-自定义生成策略"><a href="#4-2-自定义生成策略" class="headerlink" title="4.2 自定义生成策略"></a>4.2 自定义生成策略</h6><ul>
<li>可以通过修改代码生成器的实现逻辑，改变代码生成的规则。例如，可以在生成时自动添加业务逻辑或增加额外的注释信息。</li>
</ul>
</blockquote>
<h6 id="5-常见的使用场景"><a href="#5-常见的使用场景" class="headerlink" title="5. 常见的使用场景"></a>5. 常见的使用场景</h6><blockquote>
<ul>
<li>快速构建 CRUD 模块：对于后台管理系统，CRUD 模块是常见需求，代码生成器可以大幅减少重复的 CRUD 开发工作。</li>
<li>原型开发：在项目初期快速生成系统的原型，帮助团队进行功能验证和需求讨论。</li>
<li>代码模板统一：通过定制模板，可以使项目中的代码风格和规范统一，提高代码的可维护性。</li>
</ul>
</blockquote>
<h4 id="三、自定应化若以框架"><a href="#三、自定应化若以框架" class="headerlink" title="三、自定应化若以框架"></a>三、自定应化若以框架</h4><blockquote>
<p>前言：这部分内容我将会根据实际业务需求来改造若依框架，内容参考 B 站黑马若依“帝可得”项目教程，对若依原理感兴趣的可以去看一下原视频，个人感觉讲的还是比较清楚的。</p>
</blockquote>
<h6 id="1-构建基本框架"><a href="#1-构建基本框架" class="headerlink" title="1.构建基本框架"></a>1.构建基本框架</h6><blockquote>
<p>首先让我们来创建三张表，下面是建表语句：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">CREATE TABLE `tb_region` (</span><br><span class="line">  `id` INT AUTO_INCREMENT COMMENT <span class="string">&#x27;主键id&#x27;</span> PRIMARY KEY,</span><br><span class="line">  `region_name` VARCHAR(<span class="number">255</span>) NOT NULL COMMENT <span class="string">&#x27;区域名称&#x27;</span>,</span><br><span class="line">  `create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT <span class="string">&#x27;创建时间&#x27;</span>,</span><br><span class="line">  `update_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT <span class="string">&#x27;修改时间&#x27;</span>,</span><br><span class="line">  `create_by` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;创建人&#x27;</span>,</span><br><span class="line">  `update_by` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;修改人&#x27;</span>,</span><br><span class="line">  `remark` TEXT COMMENT <span class="string">&#x27;备注&#x27;</span></span><br><span class="line">) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=<span class="string">&#x27;区域表&#x27;</span>;</span><br><span class="line"></span><br><span class="line">-- 插入测试数据</span><br><span class="line">INSERT INTO `tb_region` (`region_name`,`remark`) VALUES (<span class="string">&#x27;北京市朝阳区&#x27;</span>,<span class="string">&#x27;北京市朝阳区&#x27;</span>), (<span class="string">&#x27;北京市海淀区&#x27;</span>,<span class="string">&#x27;北京市海淀区&#x27;</span>), (<span class="string">&#x27;北京市东城区&#x27;</span>,<span class="string">&#x27;北京市东城区&#x27;</span>);</span><br><span class="line"></span><br><span class="line">CREATE TABLE `tb_partner` (</span><br><span class="line">  `id` INT AUTO_INCREMENT COMMENT <span class="string">&#x27;主键id&#x27;</span> PRIMARY KEY,</span><br><span class="line">  `partner_name` VARCHAR(<span class="number">255</span>) NOT NULL COMMENT <span class="string">&#x27;合作商名称&#x27;</span>,</span><br><span class="line">  `contact_person` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;联系人&#x27;</span>,</span><br><span class="line">  `contact_phone` VARCHAR(<span class="number">15</span>) COMMENT <span class="string">&#x27;联系电话&#x27;</span>,</span><br><span class="line">  `profit_ratio` INT COMMENT <span class="string">&#x27;分成比例&#x27;</span>,</span><br><span class="line">  `account` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;账号&#x27;</span>,</span><br><span class="line">  `password` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;密码&#x27;</span>,</span><br><span class="line">  `create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT <span class="string">&#x27;创建时间&#x27;</span>,</span><br><span class="line">  `update_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT <span class="string">&#x27;修改时间&#x27;</span>,</span><br><span class="line">  `create_by` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;创建人&#x27;</span>,</span><br><span class="line">  `update_by` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;修改人&#x27;</span>,</span><br><span class="line">  `remark` TEXT COMMENT <span class="string">&#x27;备注&#x27;</span></span><br><span class="line">) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=<span class="string">&#x27;合作商表&#x27;</span>;</span><br><span class="line"></span><br><span class="line">-- 插入测试数据</span><br><span class="line">INSERT INTO `tb_partner` (`partner_name`, `contact_person`, `contact_phone`, `profit_ratio`, `account`, `password`) VALUES</span><br><span class="line">(<span class="string">&#x27;合作商A&#x27;</span>, <span class="string">&#x27;张三&#x27;</span>, <span class="string">&#x27;13800138000&#x27;</span>, <span class="number">30</span>, <span class="string">&#x27;a001&#x27;</span>, <span class="string">&#x27;pwdA&#x27;</span>),</span><br><span class="line">(<span class="string">&#x27;合作商B&#x27;</span>, <span class="string">&#x27;李四&#x27;</span>, <span class="string">&#x27;13912345678&#x27;</span>, <span class="number">25</span>, <span class="string">&#x27;b002&#x27;</span>, <span class="string">&#x27;pwdB&#x27;</span>);</span><br><span class="line"></span><br><span class="line">CREATE TABLE `tb_node` (</span><br><span class="line">  `id` INT AUTO_INCREMENT COMMENT <span class="string">&#x27;主键id&#x27;</span> PRIMARY KEY,</span><br><span class="line">  `node_name` VARCHAR(<span class="number">255</span>) NOT NULL COMMENT <span class="string">&#x27;点位名称&#x27;</span>,</span><br><span class="line">  `address` VARCHAR(<span class="number">255</span>) NOT NULL COMMENT <span class="string">&#x27;详细地址&#x27;</span>,</span><br><span class="line">  `business_type` INT COMMENT <span class="string">&#x27;商圈类型&#x27;</span>,</span><br><span class="line">  `region_id` INT COMMENT <span class="string">&#x27;区域ID&#x27;</span>,</span><br><span class="line">  `partner_id` INT COMMENT <span class="string">&#x27;合作商ID&#x27;</span>,</span><br><span class="line">  `create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT <span class="string">&#x27;创建时间&#x27;</span>,</span><br><span class="line">  `update_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT <span class="string">&#x27;修改时间&#x27;</span>,</span><br><span class="line">  `create_by` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;创建人&#x27;</span>,</span><br><span class="line">  `update_by` VARCHAR(<span class="number">64</span>) COMMENT <span class="string">&#x27;修改人&#x27;</span>,</span><br><span class="line">  `remark` TEXT COMMENT <span class="string">&#x27;备注&#x27;</span>,</span><br><span class="line">  FOREIGN <span class="title function_">KEY</span> <span class="params">(`region_id`)</span> REFERENCES `tb_region`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,</span><br><span class="line">  FOREIGN <span class="title function_">KEY</span> <span class="params">(`partner_id`)</span> REFERENCES `tb_partner`(`id`) ON DELETE CASCADE ON UPDATE CASCADE</span><br><span class="line">) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=<span class="string">&#x27;点位表&#x27;</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 插入测试数据</span><br><span class="line">-- 假设区域ID为<span class="number">1</span>对应<span class="string">&#x27;北京市朝阳区&#x27;</span>，合作商ID为<span class="number">1</span>对应<span class="string">&#x27;合作商A&#x27;</span></span><br><span class="line">INSERT INTO `tb_node` (`node_name`, `address`, `business_type`, `region_id`, `partner_id`) VALUES</span><br><span class="line">(<span class="string">&#x27;三里屯点位&#x27;</span>, <span class="string">&#x27;北京市朝阳区三里屯路&#x27;</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>),</span><br><span class="line">(<span class="string">&#x27;五道口点位&#x27;</span>, <span class="string">&#x27;北京市海淀区五道口&#x27;</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>

<blockquote>
<p>然后是这三张表之间的关系：可以看到区域表跟点位表是一对多的关系，合作商表与点位表也是一对多的关系，一个区域里面或者是一个合作商都可以拥有多个点位。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_a0178a50.png" alt="pic_a0178a50.png"></p>
<blockquote>
<p>然后我们使用若依的代码生成器来生成区域管理相关代码</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_95dbd639.png" alt="pic_95dbd639.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_19566da6.png" alt="pic_19566da6.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_a1491b66.png" alt="pic_a1491b66.png"></p>
<blockquote>
<p>然后将生成的代码分别导入到你的前后端项目中，main 文件夹中生成的后端代码，vue 文件夹中生成的前端代码，下面的三条 sql 脚本是若依框架的动态菜单表，将这三张表导入以后就可以使用若依的菜单管理功能对这三张菜单进行动态管理。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_72575bda.png" alt="pic_72575bda.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_0f44480a.png" alt="pic_0f44480a.png"> <img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_97c44b56.png" alt="pic_97c44b56.png"></p>
<blockquote>
<p>然后启动项目进入到区域管理菜单模块，基础界面如下图所示：</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_61267570.png" alt="pic_61267570.png"></p>
<h6 id="2-自定义框架"><a href="#2-自定义框架" class="headerlink" title="2.自定义框架"></a>2.自定义框架</h6><h6 id="2-1-问题分析"><a href="#2-1-问题分析" class="headerlink" title="2.1 问题分析"></a>2.1 问题分析</h6><blockquote>
<p>可以看到，若依帮我们生成的代码还是有很多问题的：</p>
</blockquote>
<blockquote>
<p>1.首先就是列表名 id，用 id 来当列表名其实是若依默认的，但这显然是不合适的的，所以我们要把 id 改为序号。</p>
<p>2.其次就是我们在刚刚建表时就对这三张表分析过了，区域表显然是更点位表有关联的，但是在页面上并没有体现出来，我们是想要在区域菜单中展示对应区域有多少个点位的！</p>
<p>3.除了基本的修改和删除，如果我还想要增加一个按键叫做“查看详情”，要求点击该按键后弹出该区域的详细信息因该怎么实现？</p>
</blockquote>
<h6 id="2-2-解决方法"><a href="#2-2-解决方法" class="headerlink" title="2.2 解决方法"></a>2.2 解决方法</h6><blockquote>
<p>下面我们针对这些问题一一来解决</p>
</blockquote>
<blockquote>
<p>首先是序号名称问题，我们将 lable 标签中的值修改掉就好了</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">&lt;el-table-column label=<span class="string">&quot;序号&quot;</span> align=<span class="string">&quot;center&quot;</span> prop=<span class="string">&quot;id&quot;</span> /&gt;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>然后是对应区域点位数量的问题，这个问题我们需要将其拆封成两个部分，第一部分是后端的视图封装，我们定义一个 RegionVo 类，来封装所要在前端展示的数据，由前面的分析可知我们希望展示点位数据，所以先继承原有的 Regon 类，然后在此基础上添加一个 nodeCount 变量用来存储对应的点位数量（变量名的定义因该尽量跟数据库对应数据类型的名字一样，并采用驼峰式命名风格）</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">&lt;!-- 使用驼峰命名法转换字段 --&gt;</span><br><span class="line">&lt;setting name=<span class="string">&quot;mapUnderscoreToCamelCase&quot;</span> value=<span class="string">&quot;true&quot;</span>/&gt;</span><br></pre></td></tr></table></figure>

<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_549657fb.png" alt="pic_549657fb.png"></p>
<blockquote>
<p>然后就是实现点位数量的查询，这里有两种实现思路</p>
<p>（1）同步存储：在区域表中有点位数的字段，当点位发生变化时，同步区域表中的点位数。</p>
<ul>
<li>优点：由于是单表查询操作，查询列表效率最高。</li>
<li>缺点：需要在点位增删改时修改区域表中的数据，有额外的开销，数据也可能不一致。</li>
</ul>
<p>（2）关联查询：编写关联查询语句，在 mapper 层封装。</p>
<ul>
<li>优点：实时查询，数据 100%正确，不需要单独维护。</li>
<li>缺点：SQL 语句较复杂，如果数据量大，性能比较低。</li>
</ul>
<p>由于区域和点位表，记录个数都不是很多，所以我们采用关联查询这种方案。</p>
</blockquote>
<blockquote>
<p>SQL 查询：先聚合统计每个区域的点位数，然后与区域表进行关联查询</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">select r.id, r.region_name, r.remark, ifnull(n.node_count, <span class="number">0</span>) as node_count</span><br><span class="line">from  tb_region r left <span class="title function_">join</span></span><br><span class="line"><span class="params">(select region_id, count(*)</span> as node_count</span><br><span class="line">from tb_node group by region_id) n on r.id = n.region_id</span><br></pre></td></tr></table></figure>

<blockquote>
<p>先在查询中测试这段 sql 代码，运行结果没问题后再放入 mapper.xml 中。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_dd2a6197.png" alt="pic_dd2a6197.png"></p>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_c878a3e5.png" alt="pic_c878a3e5.png"></p>
<blockquote>
<p>加 where 的原因是为了动态地生成 SQL 查询的 <code>WHERE</code> 子句，它可以帮助避免因条件拼接时的语法错误，自动处理 <code>WHERE</code> 关键字和 <code>AND</code> 的连接问题。</p>
</blockquote>
<blockquote>
<p>然后即使基本的 mapper 层、service 层、servviceipml 层、controller 层的编写，这里就快速过一下代码。</p>
</blockquote>
<p>RegionMapper</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 查询区域管理列表</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> region</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> RegionVo集合</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> List&lt;RegionVo&gt; <span class="title function_">selectRegionVoList</span><span class="params">(Region region)</span>;</span><br></pre></td></tr></table></figure>

<p>IRegionService</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 查询区域管理列表，带点位数量</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> region 区域管理</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> RegionVo集合</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> List&lt;RegionVo&gt; <span class="title function_">selectRegionVoList</span><span class="params">(Region region)</span>;</span><br></pre></td></tr></table></figure>

<p>RegionServiceImpl</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 查询区域管理列表</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> region</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> RegionVo集合</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> List&lt;RegionVo&gt; <span class="title function_">selectRegionVoList</span><span class="params">(Region region)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> regionMapper.selectRegionVoList(region);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>RegionController</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 查询区域管理列表</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@PreAuthorize(&quot;@ss.hasPermi(&#x27;manage:region:list&#x27;)&quot;)</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/list&quot;)</span></span><br><span class="line"><span class="keyword">public</span> TableDataInfo <span class="title function_">list</span><span class="params">(Region region)</span></span><br><span class="line">&#123;</span><br><span class="line">    startPage();</span><br><span class="line">    List&lt;RegionVo&gt; voList = regionService.selectRegionVoList(region);</span><br><span class="line">    <span class="keyword">return</span> getDataTable(voList);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>到此后端代码改造完成，需要注意的是，除了在 Controller 层中对原有的 list 方法进行修改以外，剩下的几层都是新增方法，不要把之前的方法改掉！不然由于有一些接口比如数据导出，还是使用的 selectRegionList（）方法就会报错！</p>
</blockquote>
<blockquote>
<p>接下来让我们把目光转向前端，由于后端已经数据封装好了，这里只需要在 el-table-column 标签中指定 prop 属性即可。</p>
</blockquote>
<p>region&#x2F;index.vue</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">&lt;el-table-column label=<span class="string">&quot;点位数&quot;</span> align=<span class="string">&quot;center&quot;</span> prop=<span class="string">&quot;nodeCount&quot;</span> /&gt;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>修改完成后重新启动项目查看界面，没有问题点位数据成功显示！</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_884739fb.png" alt="pic_884739fb.png"></p>
<blockquote>
<p>没有显示成功的可以打开 F12 然后点击一下重置按钮看一下数据返回没有，如果有下面的数据就证明后端没有问题，检查前端代码写错没有，如果连数据都没有返回，就证明是后端代码哪里写错了，以我的经验来看一般都是数据库查询的时候出问题。</p>
</blockquote>
<blockquote>
<p>遇到 bug 的时候不要怕！根据报错信息一步步寻找错误，学会使用断点进行调试和 log.info(需用引入 SLF4J 依赖)输出日志信息，修改 bug 的过程就是你对项目结构进一步加深了解的过程！</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_c82ce8dc.png" alt="pic_c82ce8dc.png"></p>
<blockquote>
<p>最后我们来填第三个坑，实现查看详情按钮。</p>
</blockquote>
<blockquote>
<p>还是先来分析一下，我们最后想要实现下图的效果，点击查询详情后弹出下面的提示框，提示框中显示了区域名称和包含的点位，显然点位是用一个 List<NodeVo> 对象来存储的，这里又涉及到一个坑了，设备数量在哪里呢？这里为了不再增加复杂度并且考虑到连贯性的关系，就不再对点位表进行改造了，我们修改一下需求，只显示区域包括的点位名称，不显示设备数量。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_9bd96557.png" alt="pic_9bd96557.png"></p>
<blockquote>
<p>要查询点位数据，我们就要用到前端的 node.js 中的 listNode 方法</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 查询点位管理列表</span></span><br><span class="line">export function <span class="title function_">listNode</span><span class="params">(query)</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> request(&#123;</span><br><span class="line">    url: <span class="string">&#x27;/manage/node/list&#x27;</span>,</span><br><span class="line">    method: <span class="string">&#x27;get&#x27;</span>,</span><br><span class="line">    params: query</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>该方法调用后端的 list 方法查询点位数据</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 查询点位管理列表</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@PreAuthorize(&quot;@ss.hasPermi(&#x27;manage:node:list&#x27;)&quot;)</span></span><br><span class="line"> <span class="meta">@GetMapping(&quot;/list&quot;)</span></span><br><span class="line"> <span class="keyword">public</span> TableDataInfo <span class="title function_">list</span><span class="params">(Node node)</span></span><br><span class="line">    &#123;</span><br><span class="line">        startPage();</span><br><span class="line">        List&lt;Node&gt; list = nodeService.selectNodeList(node);</span><br><span class="line">        <span class="keyword">return</span> getDataTable(list);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>然后我们在<code>&lt;script&gt;</code>中来编写 <code>getRegionInfo</code> 方法，并绑定按键</p>
</blockquote>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-button</span></span></span><br><span class="line"><span class="tag">  <span class="attr">link</span></span></span><br><span class="line"><span class="tag">  <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span></span></span><br><span class="line"><span class="tag">  @<span class="attr">click</span>=<span class="string">&quot;getRegionInfo(scope.row)&quot;</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-hasPermi</span>=<span class="string">&quot;[&#x27;manage:node:list&#x27;]&quot;</span></span></span><br><span class="line"><span class="tag">  &gt;</span>查看详情&lt;/el-button</span><br><span class="line">&gt;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>记得引入 js 代码</p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;</span><br><span class="line">  listRegion,</span><br><span class="line">  getRegion,</span><br><span class="line">  delRegion,</span><br><span class="line">  addRegion,</span><br><span class="line">  updateRegion,</span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">&quot;@/api/manage/region&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; listNode &#125; <span class="keyword">from</span> <span class="string">&quot;@/api/manage/node&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; loadAllParams &#125; <span class="keyword">from</span> <span class="string">&quot;@/api/page&quot;</span>;</span><br></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">/* 查看详情按钮操作 */</span></span><br><span class="line"><span class="keyword">const</span> nodeList = <span class="title function_">ref</span>([]);</span><br><span class="line"><span class="keyword">const</span> regionInfoOpen = <span class="title function_">ref</span>(<span class="literal">false</span>);</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getRegionInfo</span>(<span class="params">row</span>) &#123;</span><br><span class="line">  <span class="comment">// 查询区域信息</span></span><br><span class="line">  <span class="title function_">reset</span>();</span><br><span class="line">  <span class="keyword">const</span> _id = row.<span class="property">id</span>;</span><br><span class="line">  <span class="title function_">getRegion</span>(_id).<span class="title function_">then</span>(<span class="function">(<span class="params">response</span>) =&gt;</span> &#123;</span><br><span class="line">    form.<span class="property">value</span> = response.<span class="property">data</span>;</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="comment">// 查询点位列表</span></span><br><span class="line">  loadAllParams.<span class="property">regionId</span> = row.<span class="property">id</span>;</span><br><span class="line">  <span class="title function_">listNode</span>(loadAllParams).<span class="title function_">then</span>(<span class="function">(<span class="params">response</span>) =&gt;</span> &#123;</span><br><span class="line">    nodeList.<span class="property">value</span> = response.<span class="property">rows</span>;</span><br><span class="line">  &#125;);</span><br><span class="line">  regionInfoOpen.<span class="property">value</span> = <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>下面是对这一段 javascript 代码的详细解释，本问题的关键所在就是这段代码，有了这段代码才能够拿到数据。</p>
<ol>
<li><code>const nodeList = ref([]);</code></li>
</ol>
<ul>
<li>这行代码定义了一个响应式变量 <code>nodeList</code>，初始值为空数组。</li>
<li><code>ref</code> 是 Vue.js Composition API 提供的用于创建响应式数据的函数，<code>nodeList</code> 会随着值的变化自动触发视图更新。</li>
</ul>
<ol start="2">
<li><code>const regionInfoOpen = ref(false);</code></li>
</ol>
<ul>
<li>定义了另一个响应式变量 <code>regionInfoOpen</code>，初始值为 <code>false</code>。</li>
<li>这个变量用来控制区域信息详情的显示状态，当 <code>regionInfoOpen</code> 为 <code>true</code> 时，详情会显示。</li>
</ul>
<ol start="3">
<li><code>function getRegionInfo(row) &#123; ... &#125;</code></li>
</ol>
<ul>
<li>定义了一个函数 <code>getRegionInfo</code>，用于处理查看区域详情的操作。</li>
<li>参数 <code>row</code> 是一个对象，通常表示区域的某一行数据。</li>
</ul>
<ol start="4">
<li><code>reset();</code></li>
</ol>
<ul>
<li>调用了一个 <code>reset()</code> 函数，可能用于重置表单或页面状态，以清除之前的数据。具体的实现不在这段代码中。</li>
</ul>
<ol start="5">
<li><code>const _id = row.id</code></li>
</ol>
<ul>
<li>获取 <code>row</code> 对象的 <code>id</code> 属性值，并将其存储在 <code>_id</code> 变量中，用于后续的查询操作。</li>
</ul>
<ol start="6">
<li><code>getRegion(_id).then(response =&gt; &#123; ... &#125;)</code></li>
</ol>
<ul>
<li>调用 <code>getRegion</code> 方法获取区域的详细信息，<code>_id</code> 作为查询参数。</li>
<li><code>getRegion</code> 应该是一个返回 Promise 的函数，使用 <code>.then</code> 方法处理异步响应。</li>
<li>如果请求成功，<code>response.data</code> 会赋值给 <code>form.value</code>，其中 <code>form</code> 应该是另一个 <code>ref</code> 响应式变量，用于绑定表单数据。</li>
</ul>
<ol start="7">
<li><code>loadAllParams.regionId = row.id;</code></li>
</ol>
<ul>
<li>更新 <code>loadAllParams</code> 对象的 <code>regionId</code> 属性为当前区域的 <code>id</code>，用于查询点位列表。</li>
</ul>
<ol start="8">
<li><code>listNode(loadAllParams).then(response =&gt; &#123; ... &#125;)</code></li>
</ol>
<ul>
<li>调用 <code>listNode</code> 方法获取与当前区域相关的点位列表，<code>loadAllParams</code> 作为查询参数。</li>
<li><code>listNode</code> 也是一个返回 Promise 的函数，异步处理响应结果。</li>
<li>请求成功时，将返回的数据（<code>response.rows</code>）赋值给 <code>nodeList.value</code>，更新点位列表。</li>
</ul>
<ol start="9">
<li><code>regionInfoOpen.value = true;</code></li>
</ol>
<ul>
<li>将 <code>regionInfoOpen</code> 的值设置为 <code>true</code>，表示区域信息详情的弹窗或面板应该显示。</li>
</ul>
</blockquote>
<blockquote>
<p>理解完了这段代码后，最后就是编写一个提示框，绑定对应的数据即可！</p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">&lt;!-- 查看详情对话框 --&gt;</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">el-dialog</span> <span class="attr">title</span>=<span class="string">&quot;区域详情&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;regionInfoOpen&quot;</span> <span class="attr">width</span>=<span class="string">&quot;500px&quot;</span> <span class="attr">append-to-body</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">el-form-item</span> <span class="attr">label</span>=<span class="string">&quot;区域名称&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;regionName&quot;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">el-input</span> <span class="attr">v-model</span>=<span class="string">&quot;form.regionName&quot;</span> <span class="attr">disabled</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;/<span class="name">el-form-item</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">label</span>&gt;</span>包含点位：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">el-table</span> <span class="attr">:data</span>=<span class="string">&quot;nodeList&quot;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">&quot;序号&quot;</span> <span class="attr">type</span>=<span class="string">&quot;index&quot;</span> <span class="attr">width</span>=<span class="string">&quot;50&quot;</span> <span class="attr">align</span>=<span class="string">&quot;center&quot;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">&quot;点位名称&quot;</span> <span class="attr">align</span>=<span class="string">&quot;center&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;nodeName&quot;</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;/<span class="name">el-table</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">el-dialog</span>&gt;</span></span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>欧克，做完这一步之后就可以重新启动项目进行测试了。</p>
</blockquote>
<p><img src="/img/loading.gif" data-original="https://api.smain.cn/pics/pic_92b16645.png" alt="pic_92b16645.png"></p>
<blockquote>
<p>可以看到点击查看详情后成功返回提示框！</p>
</blockquote>
<blockquote>
<p>到此，自定义若依框架的一些基本步骤都已经演示完毕，如果你认真的看到了这里并且自己动手试验了，那么我相信你一定对若依框架有了更深刻的了解和认识，当然，由于本文只是若依的基础入门讲解，所以只是定义了一些基础的功能，若依能做的远远不止这些，例如定时任务调度，数据可视化报表等等，笔者也是水平有限，如果有什么错误敬请指正，希望能和大家一起学习一起进步！</p>
</blockquote>
<h4 id="四、结语"><a href="#四、结语" class="headerlink" title="四、结语"></a>四、结语</h4><blockquote>
<p>到这里，若依框架的基本使用方法已经介绍完毕。需要注意的是，虽然若依的代码生成器极大地提高了开发效率，方便快捷地生成基本的增删改查功能，但对于较为复杂的业务场景，例如多表联查或复杂的业务逻辑处理，仍需要开发者自行进行调整和优化。这也为我们提供了更多的灵活性，可以根据实际需求对代码进行更深入的定制化开发。</p>
</blockquote>
<blockquote>
<p>前路漫漫道阻且长，砥砺前行与君共勉！</p>
</blockquote>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta"><i class="fas fa-circle-user fa-fw"></i>文章作者: </span><span class="post-copyright-info"><a href="https://ywj-ch.github.io">爱吃薯片的熊猫</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta"><i class="fas fa-square-arrow-up-right fa-fw"></i>文章链接: </span><span class="post-copyright-info"><a href="https://ywj-ch.github.io/2024/10/24/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0/">https://ywj-ch.github.io/2024/10/24/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta"><i class="fas fa-circle-exclamation fa-fw"></i>版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来源 <a href="https://ywj-ch.github.io" target="_blank">爱吃薯片的熊猫の技术小站</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/springboot/">springboot</a></div><div class="post-share"><div class="social-share" data-image="/img/%E5%9F%BA%E4%BA%8E%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84SpringBoot%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0.png" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://lib.baomitu.com/social-share.js/1.0.16/css/share.min.css" media="print" onload="this.media='all'"><script src="https://lib.baomitu.com/social-share.js/1.0.16/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><a class="pagination-related full-width" href="/2025/01/04/%E7%94%A8Python%E4%B8%8EFiddler%E5%AE%9E%E7%8E%B0%E5%9B%BE%E4%B9%A6%E9%A6%86%E5%BA%A7%E4%BD%8D%E8%87%AA%E5%8A%A8%E9%A2%84%E7%BA%A6%EF%BC%9A%E5%AE%9E%E6%88%98%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/" title="用Python与Fiddler实现图书馆座位自动预约：实战经验分享"><img class="cover" src="/img/loading.gif" data-original="/img/%E7%94%A8Python%E4%B8%8EFiddler%E5%AE%9E%E7%8E%B0%E5%9B%BE%E4%B9%A6%E9%A6%86%E5%BA%A7%E4%BD%8D%E8%87%AA%E5%8A%A8%E9%A2%84%E7%BA%A6%EF%BC%9A%E5%AE%9E%E6%88%98%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="info text-right"><div class="info-1"><div class="info-item-1">下一篇</div><div class="info-item-2">用Python与Fiddler实现图书馆座位自动预约：实战经验分享</div></div><div class="info-2"><div class="info-item-1"> 前言： 期末周图书馆座位总是供不应求，每天早上七点开始预约，不到十分钟位置就被抢光。对于我们这些爱睡懒觉的人来说，简直是噩梦！而恰好这学期我正在学习计算机网络课程，何不趁机动手写一个自动预约程序，解决这个问题呢？于是这篇博客应运而生。 免责声明： 本博客仅供计算机网络爱好者学习交流使用，请勿用于非法用途！  目录 一、需求分析 二、开发工具准备 三、功能实现 一、需求分析 我们的目标很明确，那就是使用自动化脚本实现图书馆座位的预约。我所在的学校由于只能通过微信公众号来进行预约，所以相较于能够直接在网站上预约的学校来说，数据抓包相对复杂一点，所以才会用到 fidder，不然直接浏览器 F12 就可以直接看数据包了。  让我们来分析一下要干些什么事情：   使用电脑登陆微信，进入公众号模拟预约 使用 fidder 对刚才的操作进行抓包 对数据包经行分析，提取出对应的用户登录数据以及座位预约信息 使用 Python 的 requests 库模拟用户向图书馆服务器发送预约请求 编辑定时器固定在早上 7...</div></div></div></a></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info text-center"><div class="avatar-img"><img src="/img/loading.gif" data-original="/img/butterfly-icon.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info-name">爱吃薯片的熊猫</div><div class="author-info-description">Dream big Work hard Stay focused</div><div class="site-data"><a href="/archives/"><div class="headline">文章</div><div class="length-num">6</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">9</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">3</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/Ywj-ch"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons"><a class="social-icon" href="https://blog.csdn.net/m0_74123949" target="_blank" title="CSDN"><i class="fas fa-book" style="color: #d81e06;"></i></a><a class="social-icon" href="https://gitee.com/Ywj-ee" target="_blank" title="Gitee"><i class="fas fa-code-branch" style="color: #C71D23;"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">欢迎来到我的博客！</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%89%8D%E8%A8%80"><span class="toc-number">1.</span> <span class="toc-text">前言</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%80%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E8%8B%A5%E4%BE%9D%EF%BC%9F"><span class="toc-number">2.</span> <span class="toc-text">一、什么是若依？</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E6%A6%82%E8%BF%B0"><span class="toc-number">2.1.</span> <span class="toc-text">1.概述</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84%E7%89%B9%E7%82%B9"><span class="toc-number">2.2.</span> <span class="toc-text">2.若依框架的特点</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84"><span class="toc-number">2.3.</span> <span class="toc-text">3.若依框架的目录结构</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BA%8C%E3%80%81%E8%8B%A5%E4%BE%9D%E6%A1%86%E6%9E%B6%E7%9A%84%E9%A1%B9%E7%9B%AE%E6%90%AD%E5%BB%BA"><span class="toc-number">3.</span> <span class="toc-text">二、若依框架的项目搭建</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%90%8E%E7%AB%AF%E9%A1%B9%E7%9B%AE%E5%88%9D%E5%A7%8B%E5%8C%96%E9%85%8D%E7%BD%AE"><span class="toc-number">3.1.</span> <span class="toc-text">1.后端项目初始化配置</span></a><ol class="toc-child"><li class="toc-item toc-level-6"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93"><span class="toc-number">3.1.1.</span> <span class="toc-text">配置数据库</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE-Redis-%E7%BC%93%E5%AD%98"><span class="toc-number">3.1.2.</span> <span class="toc-text">配置 Redis 缓存</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86"><span class="toc-number">3.1.3.</span> <span class="toc-text">依赖管理</span></a></li></ol></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%90%AF%E5%8A%A8%E9%A1%B9%E7%9B%AE"><span class="toc-number">3.2.</span> <span class="toc-text">2.启动项目</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E7%95%8C%E9%9D%A2%E5%B1%95%E7%A4%BA"><span class="toc-number">3.3.</span> <span class="toc-text">3.界面展示</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-%E5%8A%9F%E8%83%BD%E8%AF%A6%E8%AE%B2"><span class="toc-number">3.4.</span> <span class="toc-text">4.功能详讲</span></a><ol class="toc-child"><li class="toc-item toc-level-6"><a class="toc-link" href="#1-%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86"><span class="toc-number">3.4.1.</span> <span class="toc-text">1. 系统管理</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-%E7%B3%BB%E7%BB%9F%E7%9B%91%E6%8E%A7"><span class="toc-number">3.4.2.</span> <span class="toc-text">2. 系统监控</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#3-%E7%B3%BB%E7%BB%9F%E5%B7%A5%E5%85%B7"><span class="toc-number">3.4.3.</span> <span class="toc-text">3. 系统工具</span></a></li></ol></li><li class="toc-item toc-level-5"><a class="toc-link" href="#5-%E8%8B%A5%E4%BE%9D%E7%9A%84%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E5%99%A8%E5%8A%9F%E8%83%BD"><span class="toc-number">3.5.</span> <span class="toc-text">5.若依的代码生成器功能</span></a><ol class="toc-child"><li class="toc-item toc-level-6"><a class="toc-link" href="#1-generator%E6%A8%A1%E5%9D%97%E7%9A%84%E4%B8%BB%E8%A6%81%E5%8A%9F%E8%83%BD"><span class="toc-number">3.5.1.</span> <span class="toc-text">1. generator模块的主要功能</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-generator%E6%A8%A1%E5%9D%97%E7%9A%84%E4%BD%BF%E7%94%A8%E6%AD%A5%E9%AA%A4"><span class="toc-number">3.5.2.</span> <span class="toc-text">2. generator模块的使用步骤</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-1-%E8%BF%9B%E5%85%A5%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E5%99%A8%E7%95%8C%E9%9D%A2"><span class="toc-number">3.5.3.</span> <span class="toc-text">2.1 进入代码生成器界面</span></a></li><li class="toc-item toc-level-6"><a class="toc-link"><span class="toc-number">3.5.4.</span> <span class="toc-text"></span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-2-%E9%85%8D%E7%BD%AE%E7%94%9F%E6%88%90%E5%8F%82%E6%95%B0"><span class="toc-number">3.5.5.</span> <span class="toc-text">2.2 配置生成参数</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-3-%E7%94%9F%E6%88%90%E4%BB%A3%E7%A0%81"><span class="toc-number">3.5.6.</span> <span class="toc-text">2.3 生成代码</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#3-%E7%94%9F%E6%88%90%E7%9A%84%E4%BB%A3%E7%A0%81%E7%BB%93%E6%9E%84"><span class="toc-number">3.5.7.</span> <span class="toc-text">3. 生成的代码结构</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#3-1-%E5%90%8E%E7%AB%AF%E4%BB%A3%E7%A0%81"><span class="toc-number">3.5.8.</span> <span class="toc-text">3.1 后端代码</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#3-2-%E5%89%8D%E7%AB%AF%E4%BB%A3%E7%A0%81"><span class="toc-number">3.5.9.</span> <span class="toc-text">3.2 前端代码</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#4-%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E5%99%A8%E7%9A%84%E8%87%AA%E5%AE%9A%E4%B9%89"><span class="toc-number">3.5.10.</span> <span class="toc-text">4. 代码生成器的自定义</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#4-1-%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E6%A8%A1%E6%9D%BF"><span class="toc-number">3.5.11.</span> <span class="toc-text">4.1 自定义代码生成模板</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#4-2-%E8%87%AA%E5%AE%9A%E4%B9%89%E7%94%9F%E6%88%90%E7%AD%96%E7%95%A5"><span class="toc-number">3.5.12.</span> <span class="toc-text">4.2 自定义生成策略</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#5-%E5%B8%B8%E8%A7%81%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-number">3.5.13.</span> <span class="toc-text">5. 常见的使用场景</span></a></li></ol></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%89%E3%80%81%E8%87%AA%E5%AE%9A%E5%BA%94%E5%8C%96%E8%8B%A5%E4%BB%A5%E6%A1%86%E6%9E%B6"><span class="toc-number">4.</span> <span class="toc-text">三、自定应化若以框架</span></a><ol class="toc-child"><li class="toc-item toc-level-6"><a class="toc-link" href="#1-%E6%9E%84%E5%BB%BA%E5%9F%BA%E6%9C%AC%E6%A1%86%E6%9E%B6"><span class="toc-number">4.0.1.</span> <span class="toc-text">1.构建基本框架</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A1%86%E6%9E%B6"><span class="toc-number">4.0.2.</span> <span class="toc-text">2.自定义框架</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-1-%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90"><span class="toc-number">4.0.3.</span> <span class="toc-text">2.1 问题分析</span></a></li><li class="toc-item toc-level-6"><a class="toc-link" href="#2-2-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95"><span class="toc-number">4.0.4.</span> <span class="toc-text">2.2 解决方法</span></a></li></ol></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9B%9B%E3%80%81%E7%BB%93%E8%AF%AD"><span class="toc-number">5.</span> <span class="toc-text">四、结语</span></a></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/2025/02/11/%E5%9F%BA%E4%BA%8EHexo%E6%A1%86%E6%9E%B6%E5%92%8CButterfly%E4%B8%BB%E9%A2%98%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E7%BD%91%E7%AB%99/" title="基于Hexo框架和Butterfly主题搭建个人博客网站"><img src="/img/loading.gif" data-original="/img/%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E6%95%99%E7%A8%8B.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="基于Hexo框架和Butterfly主题搭建个人博客网站"/></a><div class="content"><a class="title" href="/2025/02/11/%E5%9F%BA%E4%BA%8EHexo%E6%A1%86%E6%9E%B6%E5%92%8CButterfly%E4%B8%BB%E9%A2%98%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E7%BD%91%E7%AB%99/" title="基于Hexo框架和Butterfly主题搭建个人博客网站">基于Hexo框架和Butterfly主题搭建个人博客网站</a><time datetime="2025-02-11T13:37:26.000Z" title="发表于 2025-02-11 21:37:26">2025-02-11</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2025/02/11/Spring%20Boot%20+%20Vue%20%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB%E9%A1%B9%E7%9B%AE%E4%B8%8A%E7%BA%BF%E5%AE%9E%E8%AE%B0/" title="Spring Boot + Vue 前后端分离项目上线实记"><img src="/img/loading.gif" data-original="/img/%E9%A1%B9%E7%9B%AE%E4%B8%8A%E7%BA%BF.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Spring Boot + Vue 前后端分离项目上线实记"/></a><div class="content"><a class="title" href="/2025/02/11/Spring%20Boot%20+%20Vue%20%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB%E9%A1%B9%E7%9B%AE%E4%B8%8A%E7%BA%BF%E5%AE%9E%E8%AE%B0/" title="Spring Boot + Vue 前后端分离项目上线实记">Spring Boot + Vue 前后端分离项目上线实记</a><time datetime="2025-02-11T13:29:31.000Z" title="发表于 2025-02-11 21:29:31">2025-02-11</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2025/01/25/%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%85%A5%E9%97%A8%EF%BC%9A%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B%E8%A7%A3%E6%9E%90/" title="SpringCloud 微服务入门：服务调用流程解析"><img src="/img/loading.gif" data-original="/img/SpringCloud%20%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%85%A5%E9%97%A8%EF%BC%9A%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B%E8%A7%A3%E6%9E%90.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="SpringCloud 微服务入门：服务调用流程解析"/></a><div class="content"><a class="title" href="/2025/01/25/%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%85%A5%E9%97%A8%EF%BC%9A%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B%E8%A7%A3%E6%9E%90/" title="SpringCloud 微服务入门：服务调用流程解析">SpringCloud 微服务入门：服务调用流程解析</a><time datetime="2025-01-25T12:08:31.000Z" title="发表于 2025-01-25 20:08:31">2025-01-25</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2025/01/12/Linux%EF%BC%88Centos7%EF%BC%89%E5%AE%89%E8%A3%85docker%E3%80%81mysql%E8%B8%A9%E5%9D%91%E6%80%BB%E7%BB%93/" title="Linux（Centos7）安装docker、mysql踩坑总结"><img src="/img/loading.gif" data-original="/img/Linux%EF%BC%88Centos7%EF%BC%89%E5%AE%89%E8%A3%85docker%E3%80%81mysql%E8%B8%A9%E5%9D%91%E6%80%BB%E7%BB%93.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Linux（Centos7）安装docker、mysql踩坑总结"/></a><div class="content"><a class="title" href="/2025/01/12/Linux%EF%BC%88Centos7%EF%BC%89%E5%AE%89%E8%A3%85docker%E3%80%81mysql%E8%B8%A9%E5%9D%91%E6%80%BB%E7%BB%93/" title="Linux（Centos7）安装docker、mysql踩坑总结">Linux（Centos7）安装docker、mysql踩坑总结</a><time datetime="2025-01-12T13:05:12.000Z" title="发表于 2025-01-12 21:05:12">2025-01-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/2025/01/04/%E7%94%A8Python%E4%B8%8EFiddler%E5%AE%9E%E7%8E%B0%E5%9B%BE%E4%B9%A6%E9%A6%86%E5%BA%A7%E4%BD%8D%E8%87%AA%E5%8A%A8%E9%A2%84%E7%BA%A6%EF%BC%9A%E5%AE%9E%E6%88%98%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/" title="用Python与Fiddler实现图书馆座位自动预约：实战经验分享"><img src="/img/loading.gif" data-original="/img/%E7%94%A8Python%E4%B8%8EFiddler%E5%AE%9E%E7%8E%B0%E5%9B%BE%E4%B9%A6%E9%A6%86%E5%BA%A7%E4%BD%8D%E8%87%AA%E5%8A%A8%E9%A2%84%E7%BA%A6%EF%BC%9A%E5%AE%9E%E6%88%98%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="用Python与Fiddler实现图书馆座位自动预约：实战经验分享"/></a><div class="content"><a class="title" href="/2025/01/04/%E7%94%A8Python%E4%B8%8EFiddler%E5%AE%9E%E7%8E%B0%E5%9B%BE%E4%B9%A6%E9%A6%86%E5%BA%A7%E4%BD%8D%E8%87%AA%E5%8A%A8%E9%A2%84%E7%BA%A6%EF%BC%9A%E5%AE%9E%E6%88%98%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/" title="用Python与Fiddler实现图书馆座位自动预约：实战经验分享">用Python与Fiddler实现图书馆座位自动预约：实战经验分享</a><time datetime="2025-01-04T05:21:05.000Z" title="发表于 2025-01-04 13:21:05">2025-01-04</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2024 - 2025 By 爱吃薯片的熊猫</div><div class="footer_custom_text"><span style='color:#FFD700; font-weight:bold;'>竹子用了4年的时间， 仅仅长了3cm， 从第五年开始， 以每天30cm的速度疯狂地生长， 仅仅用了六周的时间就长到了15米。</span><br>
<span style='color:#87CEEB; font-weight:bold;'>其实，在前面的四年， 竹子将根在土壤里延伸了数百平米。 做人做事亦是如此， 不要担心你此时此刻的付出得不到回报， 因为这些付出都是为了扎根。</span>
</div></div><!-- 添加网站运行时间显示的容器--><div id="runtimeshow" data-publishDate="2025-02-01"><span>小站已运行了：</span><span id="runtime-counter"></span><span class="sand-clock">⏳</span></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="日间和夜间模式切换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><div class="js-pjax"></div><canvas id="universe"></canvas><script defer src="/js/universe.js"></script><script defer src="/js/cursor.js"></script><script src="/js/sun_moon.js" async></script><script async src="/js/fps.js"></script><script async src="/js/title.js"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="text-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="Search for Posts" type="text"/></div></div><hr/><div id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></div><!-- hexo injector body_end start --> <script data-pjax>if(document.getElementById('recent-posts') && (location.pathname ==='/'|| '/' ==='all')){
    var parent = document.getElementById('recent-posts');
    var child = '<div class="recent-post-item" style="width:100%;height: auto"><div id="catalog_magnet"><div class="magnet_item"><a class="magnet_link" href="https://ywj-ch.github.io/categories/学习笔记/"><div class="magnet_link_context" style=""><span style="font-weight:500;flex:1">📚 爱吃薯片的熊猫の学习笔记 (4)</span><span style="padding:0px 4px;border-radius: 8px;"><i class="fas fa-arrow-circle-right"></i></span></div></a></div><div class="magnet_item"><a class="magnet_link" href="https://ywj-ch.github.io/categories/个人项目/"><div class="magnet_link_context" style=""><span style="font-weight:500;flex:1">👩‍💻 爱吃薯片的熊猫の个人项目 (1)</span><span style="padding:0px 4px;border-radius: 8px;"><i class="fas fa-arrow-circle-right"></i></span></div></a></div><a class="magnet_link_more"  href="https://ywj-ch.github.io/categories" style="flex:1;text-align: center;margin-bottom: 10px;">查看更多...</a></div></div>';
    console.log('已挂载magnet')
    parent.insertAdjacentHTML("afterbegin",child)}
     </script><style>#catalog_magnet{flex-wrap: wrap;display: flex;width:100%;justify-content:space-between;padding: 10px 10px 0 10px;align-content: flex-start;}.magnet_item{flex-basis: calc(50% - 5px);background: #f2f2f2;margin-bottom: 10px;border-radius: 8px;transition: all 0.2s ease-in-out;}.magnet_item:hover{background: #69e8f2}.magnet_link_more{color:#555}.magnet_link{color:black}.magnet_link:hover{color:white}@media screen and (max-width: 600px) {.magnet_item {flex-basis: 100%;}}.magnet_link_context{display:flex;padding: 10px;font-size:16px;transition: all 0.2s ease-in-out;}.magnet_link_context:hover{padding: 10px 20px;}</style>
    <style></style><script data-pjax>
  function butterfly_swiper_injector_config(){
    var parent_div_git = document.getElementById('recent-posts');
    var item_html = '<div class="recent-post-item" style="height: auto;width: 100%"><div class="blog-slider swiper-container-fade swiper-container-horizontal" id="swiper_container"><div class="blog-slider__wrp swiper-wrapper" style="transition-duration: 0ms;"><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="2025/01/25/微服务入门：服务调用流程解析/" alt=""><img width="48" height="48" src="/img/loading.gif" data-original="/img/SpringCloud 微服务入门：服务调用流程解析.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2025-01-25</span><a class="blog-slider__title" href="2025/01/25/微服务入门：服务调用流程解析/" alt="">SpringCloud 微服务入门：服务调用流程解析</a><div class="blog-slider__text">记录了在 CentOS 7 上安装 Docker 和 MySQL 时遇到的问题及解决方案，帮助你更顺利地搭建环境，避免常见的坑。</div><a class="blog-slider__button" href="2025/01/25/微服务入门：服务调用流程解析/" alt="">详情   </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="2025/02/11/基于Hexo框架和Butterfly主题搭建个人博客网站/" alt=""><img width="48" height="48" src="/img/loading.gif" data-original="/img/个人博客搭建教程.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2025-02-11</span><a class="blog-slider__title" href="2025/02/11/基于Hexo框架和Butterfly主题搭建个人博客网站/" alt="">基于Hexo框架和Butterfly主题搭建个人博客网站</a><div class="blog-slider__text">在这篇博客中，我将带你一起走过基于 Hexo 框架搭建个人博客的全过程，同时介绍如何使用 Butterfly 主题来美化博客，使其更加符合个人风格。</div><a class="blog-slider__button" href="2025/02/11/基于Hexo框架和Butterfly主题搭建个人博客网站/" alt="">详情   </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="2025/02/11/Spring Boot + Vue 前后端分离项目上线实记/" alt=""><img width="48" height="48" src="/img/loading.gif" data-original="/img/项目上线.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2025-02-11</span><a class="blog-slider__title" href="2025/02/11/Spring Boot + Vue 前后端分离项目上线实记/" alt="">Spring Boot + Vue 前后端分离项目上线实记</a><div class="blog-slider__text">记录了一个前后端分离项目的完整部署流程。</div><a class="blog-slider__button" href="2025/02/11/Spring Boot + Vue 前后端分离项目上线实记/" alt="">详情   </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="2025/01/12/Linux（Centos7）安装docker、mysql踩坑总结/" alt=""><img width="48" height="48" src="/img/loading.gif" data-original="/img/Linux（Centos7）安装docker、mysql踩坑总结.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2025-01-12</span><a class="blog-slider__title" href="2025/01/12/Linux（Centos7）安装docker、mysql踩坑总结/" alt="">Linux（Centos7）安装docker、mysql踩坑总结</a><div class="blog-slider__text">记录了在 CentOS 7 上安装 Docker 和 MySQL 时遇到的问题及解决方案，帮助你更顺利地搭建环境，避免常见的坑。</div><a class="blog-slider__button" href="2025/01/12/Linux（Centos7）安装docker、mysql踩坑总结/" alt="">详情   </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="2025/01/04/用Python与Fiddler实现图书馆座位自动预约：实战经验分享/" alt=""><img width="48" height="48" src="/img/loading.gif" data-original="/img/用Python与Fiddler实现图书馆座位自动预约：实战经验分享.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2025-01-04</span><a class="blog-slider__title" href="2025/01/04/用Python与Fiddler实现图书馆座位自动预约：实战经验分享/" alt="">用Python与Fiddler实现图书馆座位自动预约：实战经验分享</a><div class="blog-slider__text">本文详细介绍了基于若依框架构建 SpringBoot 管理系统的学习过程，涵盖了框架的基本配置、功能实现及常见问题解决，帮助开发者快速上手和掌握若依框架。</div><a class="blog-slider__button" href="2025/01/04/用Python与Fiddler实现图书馆座位自动预约：实战经验分享/" alt="">详情   </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="2024/10/24/基于若依框架的SpringBoot管理系统学习/" alt=""><img width="48" height="48" src="/img/loading.gif" data-original="/img/基于若依框架的SpringBoot管理系统学习.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2024-10-24</span><a class="blog-slider__title" href="2024/10/24/基于若依框架的SpringBoot管理系统学习/" alt="">基于若依框架的SpringBoot管理系统学习</a><div class="blog-slider__text">本文详细介绍了基于若依框架构建 SpringBoot 管理系统的学习过程，涵盖了框架的基本配置、功能实现及常见问题解决，帮助开发者快速上手和掌握若依框架。</div><a class="blog-slider__button" href="2024/10/24/基于若依框架的SpringBoot管理系统学习/" alt="">详情   </a></div></div></div><div class="blog-slider__pagination swiper-pagination-clickable swiper-pagination-bullets"></div></div></div>';
    console.log('已挂载butterfly_swiper')
    parent_div_git.insertAdjacentHTML("afterbegin",item_html)
    }
  var elist = 'undefined'.split(',');
  var cpage = location.pathname;
  var epage = '/';
  var flag = 0;

  for (var i=0;i<elist.length;i++){
    if (cpage.includes(elist[i])){
      flag++;
    }
  }

  if ((epage ==='all')&&(flag == 0)){
    butterfly_swiper_injector_config();
  }
  else if (epage === cpage){
    butterfly_swiper_injector_config();
  }
  </script><script defer src="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js"></script><script defer data-pjax src="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper_init.js"></script><div class="js-pjax"><script async="async">var arr = document.getElementsByClassName('recent-post-item');
for(var i = 0;i<arr.length;i++){
    arr[i].classList.add('wow');
    arr[i].classList.add('animate__fadeInDown');
    arr[i].setAttribute('data-wow-duration', '2s');
    arr[i].setAttribute('data-wow-delay', '1s');
    arr[i].setAttribute('data-wow-offset', '100');
    arr[i].setAttribute('data-wow-iteration', '2');
  }</script><script async="async">var arr = document.getElementsByClassName('card-widget');
for(var i = 0;i<arr.length;i++){
    arr[i].classList.add('wow');
    arr[i].classList.add('animate__zoomIn');
    arr[i].setAttribute('data-wow-duration', '');
    arr[i].setAttribute('data-wow-delay', '');
    arr[i].setAttribute('data-wow-offset', '');
    arr[i].setAttribute('data-wow-iteration', '');
  }</script></div><script defer src="https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/wow.min.js"></script><script defer src="https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/wow_init.js"></script><!-- hexo injector body_end end -->
        <style>
            [bg-lazy] {
                background-image: none !important;
                background-color: #eee !important;
            }
        </style>
        <script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z\d\-\.\+]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(t.test(e.href)||r.test(e.href))&&(e.href=a.dataset.original)})});</script><script>(r=>{r.imageLazyLoadSetting.processImages=t;var a=r.imageLazyLoadSetting.isSPA,o=r.imageLazyLoadSetting.preloadRatio||1,d=i();function i(){var t=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")),e=Array.prototype.slice.call(document.querySelectorAll("[bg-lazy]"));return t.concat(e)}function t(t){(a||t)&&(d=i());for(var e,n=0;n<d.length;n++)0<=(e=(e=d[n]).getBoundingClientRect()).bottom&&0<=e.left&&e.top<=(r.innerHeight*o||document.documentElement.clientHeight*o)&&(()=>{var t,e,a,o,i=d[n];e=function(){d=d.filter(function(t){return i!==t}),r.imageLazyLoadSetting.onImageLoaded&&r.imageLazyLoadSetting.onImageLoaded(i)},(t=i).dataset.loaded||(t.hasAttribute("bg-lazy")?(t.removeAttribute("bg-lazy"),e&&e()):(a=new Image,o=t.getAttribute("data-original"),a.onload=function(){t.src=o,t.removeAttribute("data-original"),t.setAttribute("data-loaded",!0),e&&e()},a.onerror=function(){t.removeAttribute("data-original"),t.setAttribute("data-loaded",!1),t.src=o},t.src!==o&&(a.src=o)))})()}function e(){clearTimeout(t.tId),t.tId=setTimeout(t,500)}t(),document.addEventListener("scroll",e),r.addEventListener("resize",e),r.addEventListener("orientationchange",e)})(this);</script><script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"jsonPath":"/live2dw/assets/koharu.model.json"},"display":{"position":"left","width":150,"height":300},"mobile":{"show":false},"log":false});</script></body></html>